package repo

import (
	"context"
	"github.com/go-kratos/kratos/v2/log"
	"github.com/google/wire"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	command_service "gotham-plan-manage/internal/app/command_service"
	"gotham-plan-manage/internal/conf"
)

// ProviderSet is data providers.
var ProviderSet = wire.NewSet(NewPlanManageRepo, NewData, NewTransaction)

// Data .
type Data struct {
	db  *gorm.DB
	log *log.Helper
}

// 用来承载事务的上下文
type contextTxKey struct{}

// NewTransaction .
func NewTransaction(d *Data) command_service.Transaction {
	return d
}

// ExecTx gorm Transaction
func (d *Data) ExecTx(ctx context.Context, fn func(ctx context.Context) error) error {
	return d.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		ctx = context.WithValue(ctx, contextTxKey{}, tx)
		return fn(ctx)
	})
}

// DB 根据此方法来判断当前的 db 是不是使用 事务的 DB
func (d *Data) DB(ctx context.Context) *gorm.DB {
	tx, ok := ctx.Value(contextTxKey{}).(*gorm.DB)
	if ok {
		return tx
	}
	return d.db
}

// NewData .
func NewData(conf *conf.Data, logger1 log.Logger) (*Data, func(), error) {
	db, err := gorm.Open(
		mysql.Open(conf.Database.Source),
		&gorm.Config{
			Logger: logger.Default.LogMode(logger.Warn),
		},
	)
	sqlDB, err := db.DB()
	sqlDB.SetMaxOpenConns(30)
	sqlDB.SetMaxIdleConns(10)
	if err != nil {
		panic(err)
		//log.Fatalf("failed opening connection to mysql: %v", err)
	}
	d := &Data{
		db: db,
	}
	return d, func() {
		log.Info("message", "closing the data resources")
		sqlDB, err := db.DB()
		if err == nil && sqlDB != nil {
			_ = sqlDB.Close()
		}
	}, nil
}

// NewDB gorm Connecting to a Database
func NewDB(conf *conf.Data, logger log.Logger) *gorm.DB {
	//log := log.NewHelper(log.With(logger, "module", "order-service/data/gorm"))
	db, err := gorm.Open(mysql.Open(conf.Database.Source), &gorm.Config{})
	if err != nil {
		panic(err)
		//log.Fatalf("failed opening connection to mysql: %v", err)
	}
	return db
}
